package core.media
{
	import core.events.GlobalEvent;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundMixer;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	
	/**
	 * 声音播放器， 声音分为两种：背景音乐，音效
	 * @author Ado
	 * <p><listing version="3.0">
	 * //播放音乐
	 * SoundPlayer.getInstance().play("xxx.mp3",0);
	 * //静音模式切换
	 * SoundPlayer.getInstance().dispatchEvent(new GlobalEvent(GlobalEvent.SILIENCE_MODEL));
	 * //改变音量
	 * SoundPlayer.getInstance().effectVolumn = 0.5;
	 * SoundPlayer.getInstance().musicVolumn = 0.5;
	 * </listing></p>
	 * @custom
	 * <author email="adodo08&#64;163.com">ado</author>
	 * 
	 * @date Jul 17, 2012
	 */
	public class SoundPlayer extends EventDispatcher
	{
		/**
		 * 静音模式
		 * @eventType core.events.GlobalEvent.SILIENCE_MODEL
		 */		
		[Event(name="silience_model", type="core.events.GlobalEvent")]
		
		
		/**
		 * 声音类型：音效，只播放一遍，可同时播放多个，同一个声音同时播放的话从头开始 
		 */		
		public static const EFFECT:uint = 0;
		/**
		 * 声音类型：音乐，无限循环的播下去，直到死 
		 */		
		public static const MUSIC:uint = 1;
		//静音模式
		private var silienceMode:Boolean;
		//音乐转换
		private var musicSoundTransform:SoundTransform;
		//音效转换
		private var effectSoundTransform:SoundTransform;
		//音乐音量
		private var musicSoundValue:Number = 0;
		//音效音量
		private var effectSoundValue:Number = 0;
		/** 音乐播放器 */
		private static var musicPlayer:SoundItem;
		/** 空闲音效播放器：音效的重用率比较高，所以用Vector存放 */
		private static var freeEffects:Vector.<SoundItem>;
		/** 空闲的音乐播放器:由于背景音乐播放器的重用性不高，所以用Dictionary存放*/
		private static var freeMusic:Dictionary;
		//音乐音量
		private var _musicVolumn:Number = 0.5;
		//音效音量
		private var _effectVolumn:Number = 0.5;
		public function SoundPlayer()
		{
			musicSoundTransform = new SoundTransform();
			musicSoundTransform.volume = _musicVolumn;
			
			effectSoundTransform = new SoundTransform();
			effectSoundTransform.volume = _effectVolumn;
			
			freeEffects = new Vector.<SoundItem>();
			freeMusic = new Dictionary();
			
			addEventListener(GlobalEvent.SILIENCE_MODEL, onSilience);
		}
		/**
		 * 静音模式的切换 
		 * @param e
		 * 
		 */		
		private function onSilience(e:GlobalEvent):void
		{
			silienceMode = !silienceMode;
			if(silienceMode)
			{
				SoundMixer.stopAll();
				//effect recyle?
			}else if(musicPlayer)
			{
				musicPlayer.reset();
			}
		}
		/**
		 * 切换背景音乐的静音模式 
		 * @param value true为静音 false回复
		 * 
		 */		
		public function setMusicSilent(value:Boolean):void
		{
			if(value)
			{
				musicSoundValue = musicSoundTransform.volume;
				musicSoundTransform.volume = 0;
			}else{
				musicSoundTransform.volume = musicSoundValue;
			}
		}
		/**
		 * 切换音效的静音模式 
		 * @param value true为静音 false回复
		 * 
		 */		
		public function setEffectSilent(value:Boolean):void
		{
			if(value)
			{
				effectSoundValue = effectSoundTransform.volume;
				effectSoundTransform.volume = 0;
			}else{
				effectSoundTransform.volume = effectSoundValue;
			}
		}
		/**
		 * 音量改变 
		 * @param e
		 * 
		 */		
		private function onVolumn(e:GlobalEvent):void
		{
			var type:int = e.data.type;
			var volumn:Number = e.data.value;
			if(type)
			{
				effectSoundTransform.volume = volumn;
			}else{
				musicSoundTransform.volume = volumn;
			}
		}
		
		/**
		 * 获取音乐播放数据条 
		 * @param src	声音源
		 * @param type	声音类型
		 * @return 
		 * 
		 */		
		private function getSoundItem(src:String, type:uint=0):SoundItem
		{
			if(type==0)
			{
				var target:SoundItem = getEffectSoundPlayer(src);
			}else{
				target = getMusicPlayer(src);
			}
			return target;
		}
		/**
		 * 播放声音的指定区间
		 * @param src			声音来源
		 * @param type			声音类型 0:音效|1:音乐
		 * @param startTime		开始播放的时间，在声音的长度范围以内，默认是0，开始位置
		 * @param endTime		结尾的时间，在声音的长度范围以内，默认是-1，代表结尾位置
		 * @param repeatTimes	重复次数，默认是0||-1代表重复多次
		 * @return target		返回使用的SoundItem,用于repeatSound(soundItem)
		 * @see #repeatSound()
		 */		
		public function play(src:String, type:uint=0, startTime:int=0, repeatTimes:int=0):SoundItem
		{
			var target:SoundItem = getSoundItem(src);
			if(silienceMode == false)
				target.play(src, type, type ? musicSoundTransform : effectSoundTransform, startTime, repeatTimes);
			return target;
		}
		/**
		 * 重播声音 
		 * @param item
		 * @param repeatTimes 1
		 */		
		public function repeatSound(item:SoundItem,repeateTimes:int=0):void
		{
			item.play();
		}
		/**
		 * 取得背景音乐播放器 
		 * @param src
		 * @return 
		 * 
		 */		
		private function getMusicPlayer(src:String):SoundItem
		{
			if(musicPlayer){
				if(musicPlayer.url == src)
				{
					return musicPlayer;
				}else if(freeMusic.hasOwnProperty(src)){
					musicPlayer.stop();
					musicPlayer = freeMusic[src];
					delete freeMusic[src];
					return musicPlayer;
				}
			}
			return musicPlayer = new SoundItem();
		}
		/**
		 * 取得同类型的播放器 
		 * @param value
		 * @return 
		 * 
		 */		
		private function getEffectSoundPlayer(value:String):SoundItem
		{
			for each(var i:SoundItem in freeEffects)
			{
				if(i.url == value)
				{
					var index:int = freeEffects.indexOf(i);
					freeEffects.splice(index, 1);
					return i;
				}
			}
			return new SoundItem();
		}
		/**
		 * 回收声音对象 
		 * @param soundItem
		 * 
		 */		
		public static function recycle(soundItem:SoundItem):void
		{
			trace("recycle : "+soundItem.name);
			if(soundItem.type == 0)
			{
				if(freeEffects.indexOf(soundItem) > -1) return;
				freeEffects.push(soundItem);
			}else
			{
				freeMusic[soundItem.url]=freeMusic;
			}
		}
		
		private static var _instance:SoundPlayer;
		
		public static function getInstance():SoundPlayer
		{
			if(null == _instance)
			{
				_instance = new SoundPlayer();
			}
			return _instance;
		}

		/**
		 * 音乐音量 
		 */
		public function get musicVolumn():Number
		{
			return _musicVolumn;
		}

		/**
		 * @private
		 */
		public function set musicVolumn(value:Number):void
		{
			_musicVolumn = value;
			musicSoundTransform.volume = value;
		}

		/**
		 * 音效 
		 */
		public function get effectVolumn():Number
		{
			return _effectVolumn;
		}

		/**
		 * @private
		 */
		public function set effectVolumn(value:Number):void
		{
			_effectVolumn = value;
			effectSoundTransform.volume = value;
		}
	}//end class
}